/*
 * Copyright 2009 Eat Local Food, LLC
 * Copyright (c) 2007 osCommerce (this file was written after
 * code review of osCommerce).
 *
 * This file is part of gwtCommerce.
 *
 * gwtCommerce is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * gwtCommerce is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with gwtCommerce.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.elf.gwt.common.client.model;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONValue;

public class DetailedProductModel extends ProductModel
{	
	protected Date dateAvailable;
	protected Date dateModified;
	protected String description;
	protected int discountCategory;
	protected String image1 = null;
	protected String[] imageSize1 = null;
	protected String image2 = null;
	protected String[] imageSize2 = null;
	protected String image3 = null;
	protected String[] imageSize3 = null;
	protected String image4 = null;
	protected String[] imageSize4 = null;
	protected String image5 = null;
	protected String[] imageSize5 = null;
	protected String image6 = null;
	protected String[] imageSize6 = null;
	protected int taxClassId;
	protected String url;

	List<PriceBreakModel> priceBreaks;
	List<AttributeModel> attributes;

	//cart
	protected int cartQuantity;
	protected int cartQuantityMax;
	protected List<AttributeValueModel> cartOptions;
	protected double cartPrice;

	public DetailedProductModel()
	{
		update();
	}

	public DetailedProductModel(int categoryId, int id, String name)
	{
		update(categoryId, id, name);
	}

	public DetailedProductModel(JSONObject jsonObject, double imageWidthMax, double imageHeightMax)
	{
		this(jsonObject,imageWidthMax,imageHeightMax, false);
	}

	public DetailedProductModel(JSONObject jsonObject, double imageWidthMax, double imageHeightMax, boolean details)
	{
		super(jsonObject, imageWidthMax, imageHeightMax);
		detailedUpdate();
		dateModified = convertToDate(jsonObject, "date_modified");
		dateAvailable = convertToDate(jsonObject, "date_available");
		discountCategory = convertToInteger(jsonObject, "discount_categories_id");
		
		double imageWidth = 0;
		double imageHeight = 0;

		if (details)
		{
			description = convertToString(jsonObject, "description");
			url = convertToString(jsonObject, "url");

			image1 = convertToString(jsonObject, "image_1");
			if (image1 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_1");
				imageHeight = convertToDouble(jsonObject, "image_height_1");
				imageSize1 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}

			image2 = convertToString(jsonObject, "image_2");
			if (image2 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_2");
				imageHeight = convertToDouble(jsonObject, "image_height_2");
				imageSize2 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}

			image3 = convertToString(jsonObject, "image_3");
			if (image3 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_3");
				imageHeight = convertToDouble(jsonObject, "image_height_3");
				imageSize3 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}

			image4 = convertToString(jsonObject, "image_4");
			if (image4 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_4");
				imageHeight = convertToDouble(jsonObject, "image_height_4");
				imageSize4 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}

			image5 = convertToString(jsonObject, "image_5");
			if (image5 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_5");
				imageHeight = convertToDouble(jsonObject, "image_height_5");
				imageSize5 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}

			image6 = convertToString(jsonObject, "image_6");
			if (image6 != null)
			{
				imageWidth = convertToDouble(jsonObject, "image_width_6");
				imageHeight = convertToDouble(jsonObject, "image_height_6");
				imageSize6 = adjustedImageSize(imageWidth, imageHeight, imageWidthMax, imageHeightMax);
			}
		}
		taxClassId = convertToInteger(jsonObject, "tax_class_id");
		cartQuantity = convertToInteger(jsonObject, "cart_qty");
		
		buildPriceBreaks(jsonObject);
		buildAttributes(jsonObject);
		buildCartOptions(jsonObject);
	}

	protected void buildPriceBreaks(JSONObject jsonObject)
	{
		priceBreaks.clear();
		try {
			JSONValue addressValue = jsonObject.get("price_breaks");

			if (addressValue != null)
			{
				JSONArray jsonArray;
				if ((jsonArray = addressValue.isArray()) != null)
				{
					int sz = jsonArray.size();

					double discountPrice = 10000000000000000000.0;
					for (int i = 0; i < sz; i++)
					{
						JSONValue jsonValue = jsonArray.get(i);
						JSONObject jsonPBObject;
						if ((jsonPBObject = jsonValue.isObject()) != null)
						{
							PriceBreakModel model = new PriceBreakModel(jsonPBObject);
							addPriceBreak(model);
							if (model.getPrice() < discountPrice) discountPrice = model.getPrice();
						}
					}
					if (discountPrice < getDiscountPrice()) setDiscountPrice(discountPrice);
				}
			}
		}
		catch (Exception e) {}
	}

	protected void buildAttributes(JSONObject jsonObject)
	{
		attributes.clear();
		try {
			JSONValue addressValue = jsonObject.get("attributes");

			if (addressValue != null)
			{
				JSONArray jsonArray;
				if ((jsonArray = addressValue.isArray()) != null)
				{
					setHasAttributes(true);
					int sz = jsonArray.size();

					int prevAttributeId = -1;
					AttributeModel attributeModel = null;
					for (int i = 0; i < sz; i++)
					{
						JSONValue jsonValue = jsonArray.get(i);
						JSONObject jsonAObject;
						if ((jsonAObject = jsonValue.isObject()) != null)
						{
							AttributeValueModel model = new AttributeValueModel(jsonAObject);

							if (prevAttributeId != model.getAttributeId())
							{
								attributeModel = new AttributeModel(model.getAttributeId(), model.getAttributeName());
								addAttributes(attributeModel);
								prevAttributeId = model.getAttributeId();
							}

							attributeModel.addValues(model);
						}
					}
				}
			}
		}
		catch (Exception e) {}
	}

	public void buildCartOptions(JSONObject jsonObject)
	{
		cartOptions.clear();
		try {
			JSONValue optionValue = jsonObject.get("cart_options");

			if (optionValue != null)
			{
				JSONArray jsonArray;
				if ((jsonArray = optionValue.isArray()) != null)
				{
					int sz1 = jsonArray.size();		
					for (int j = 0; j < sz1; j++)
					{
						JSONValue jsonCAValue = jsonArray.get(j);
						JSONObject jsonCAObject;
						if ((jsonCAObject = jsonCAValue.isObject()) != null)
						{
							AttributeValueModel model = new AttributeValueModel(jsonCAObject);
							AttributeModel attributeModel = new AttributeModel(model.getAttributeId(), model.getAttributeName());
							addAttributes(attributeModel);
							attributeModel.addValues(model);
							cartOptions.add(model);
						}
					}
				}
			}
		}
		catch (Exception e) {}
	}


	public void update()
	{
		super.update();
		detailedUpdate();
	}

	public void detailedUpdate()
	{
		dateAvailable = null;
		dateModified = null;
		description = "";
		discountCategory = 0;
		image1 = null;
		imageSize1 = null;
		image2 = null;
		imageSize2 = null;
		image3 = null;
		imageSize3 = null;
		image4 = null;
		imageSize4 = null;
		image5 = null;
		imageSize5 = null;
		image6 = null;
		imageSize6 = null;
		taxClassId = 0;
		url = "";

		priceBreaks = new ArrayList<PriceBreakModel>();
		attributes = new ArrayList<AttributeModel>();

		//cart
		cartQuantity = 0;
		cartQuantityMax = 0;
		cartOptions = new ArrayList<AttributeValueModel>();
		cartPrice = 0;
	}

	public void update(int categoryId, int id, String name)
	{
		detailedUpdate();
		super.update(categoryId, id, name);
	}

	public void update(DetailedProductModel model)
	{
		super.update(model);
		dateAvailable = model.getDateAvailable();
		dateModified = model.getDateModified();
		description = model.getDescription();
		discountCategory = model.getDiscountCategory();
		image1 = model.getImage1();
		imageSize1 = model.getImageSize1();
		image2 = model.getImage2();
		imageSize2 = model.getImageSize2();
		image3 = model.getImage3();
		imageSize3 = model.getImageSize3();
		image4 = model.getImage4();
		imageSize4 = model.getImageSize4();
		image5 = model.getImage5();
		imageSize5 = model.getImageSize5();
		image6 = model.getImage6();
		imageSize6 = model.getImageSize6();
		taxClassId = model.getTaxClassId();
		url = model.getUrl();

		priceBreaks = model.getPriceBreaks();
		attributes = model.getAttributes();

		//cart
		cartQuantity = model.getCartQuantity();
		cartQuantityMax = model.getCartQuantityMax();
		cartOptions = model.getCartOptions();
		cartPrice = model.getCartPrice();
	}

	public Date getDateAvailable() {
		return dateAvailable;
	}

	public Date getDateModified() {
		return dateModified;
	}

	public String getDescription() {
		return description;
	}

	public int getDiscountCategory() {
		return discountCategory;
	}

	public int getTaxClassId() {
		return taxClassId;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public List<PriceBreakModel> getPriceBreaks() {
		return priceBreaks;
	}

	public void addPriceBreak(PriceBreakModel priceBreakModel) {
		this.priceBreaks.add(priceBreakModel);
	}

	public List<AttributeModel> getAttributes() {
		return attributes;
	}

	public void addAttributes(AttributeModel attribute) {
		this.attributes.add(attribute);
	}

	//Cart
	public List<AttributeValueModel> getCartOptions() {
		return cartOptions;
	}

	public void addCartOptions(AttributeValueModel cartOption) {
		this.cartOptions.add(cartOption);
	}

	public void clearCartOptions() {
		this.cartOptions.clear();
	}

	public int getCartQuantity() {
		return cartQuantity;
	}

	public void setCartQuantity(int cartQuantity) {
		this.cartQuantity = adjustedQuantity(cartQuantity, getQuantityBlocks());
	}

	public void setAttributes(List<AttributeModel> attributes) {
		this.attributes = attributes;
	}

	public void setCartOptions(List<AttributeValueModel> cartOptions) {
		this.cartOptions = cartOptions;
	}

	public void setPriceBreaks(List<PriceBreakModel> priceBreaks) {
		this.priceBreaks = priceBreaks;
	}

	public double getDiscountPrice(int quantity) {
		double price = 0;
		int matchingQuantity = 0;
		List<PriceBreakModel> priceBreaks = getPriceBreaks();
		int sz = priceBreaks.size();
		for (int i=0; i<sz; i++)
		{
			PriceBreakModel priceBreak = priceBreaks.get(i);
			if (quantity >= priceBreak.getQuantity())
			{
				if (priceBreak.getQuantity() > matchingQuantity)
				{
					matchingQuantity = priceBreak.getQuantity();
					price = priceBreak.getPrice();
				}
			}
		}

		return price;
	}

	public double getCartPrice() {
		return cartPrice;
	}

	public void setCartPrice(double cartPrice) {
		this.cartPrice = cartPrice;
	}

	public int getCartQuantityMax() {
		return cartQuantityMax;
	}

	public void setCartQuantityMax(int cartQuantityMax) {
		this.cartQuantityMax = cartQuantityMax;
	}

	public static ArrayList<ProductModel> buildProductModels(JSONArray jsonArray, double imageWidthMax, double imageHeightMax)
	{
		ArrayList<ProductModel> productModels = new ArrayList<ProductModel>();
		int sz = jsonArray.size();		
		for (int i = 0; i < sz; i++)
		{
			JSONValue jsonValue = jsonArray.get(i);
			JSONObject jsonObject;
			if ((jsonObject = jsonValue.isObject()) != null)
			{
				DetailedProductModel productModel = new DetailedProductModel(jsonObject, imageWidthMax, imageHeightMax);
				productModels.add(productModel);
			}
		}
		return productModels;
	}

	public String getImage1() {
		return image1;
	}

	public String getImage2() {
		return image2;
	}

	public String getImage3() {
		return image3;
	}

	public String getImage4() {
		return image4;
	}

	public String getImage5() {
		return image5;
	}

	public String getImage6() {
		return image6;
	}

	public String[] getImageSize1() {
		return imageSize1;
	}

	public String[] getImageSize2() {
		return imageSize2;
	}

	public String[] getImageSize3() {
		return imageSize3;
	}

	public String[] getImageSize4() {
		return imageSize4;
	}

	public String[] getImageSize5() {
		return imageSize5;
	}

	public String[] getImageSize6() {
		return imageSize6;
	}

	public List<String> getImages()
	{
		List<String> lst = new ArrayList<String>();
		lst.add(image);
		if (image1 != null && image1.length() > 0)lst.add(image1);
		if (image2 != null && image2.length() > 0)lst.add(image2);
		if (image3 != null && image3.length() > 0)lst.add(image3);
		if (image4 != null && image4.length() > 0)lst.add(image4);
		if (image5 != null && image5.length() > 0)lst.add(image5);
		if (image6 != null && image6.length() > 0)lst.add(image6);
		return lst;
	}

	public List<String[]> getImageSizes()
	{
		List<String[]> lst = new ArrayList<String[]>();
		lst.add(imageSize);
		if (image1 != null && image1.length() > 0)lst.add(imageSize1);
		if (image2 != null && image2.length() > 0)lst.add(imageSize2);
		if (image3 != null && image3.length() > 0)lst.add(imageSize3);
		if (image4 != null && image4.length() > 0)lst.add(imageSize4);
		if (image5 != null && image5.length() > 0)lst.add(imageSize5);
		if (image6 != null && image6.length() > 0)lst.add(imageSize6);
		return lst;
	}
}
